﻿using JetBrains.Annotations;
using Microsoft.Extensions.Localization;
using PHMEE.ToolKits;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using Volo.Abp;
using Volo.Abp.Domain.Entities.Auditing;

namespace PHMEE
{
    /// <summary>
    /// 设备
    /// </summary>
    public abstract class Equipment : CreationAuditedEntity<Guid>
    {
        protected Equipment()
        {

        }

        public Equipment(Guid id, Guid unitId, string name, string nameen, int number) : base(id)
        {
            UnitId = unitId;
            SetName(name);
            SetNameEn(nameen);
            SetNumber(number);
        }


        /// <summary>
        /// 名称
        /// </summary>
        public string Name { get; private set; }

        /// <summary>
        /// 英文名
        /// </summary>
        public string NameEn { get; private set; }

        /// <summary>
        /// 编号
        /// </summary>
        public int Number { get; private set; }

        /// <summary>
        /// 标签
        /// </summary>
        public string Tags { get; set; }

        /// <summary>
        /// 型号
        /// </summary>
        public string Model { get; set; }

        /// <summary>
        /// 类型
        /// </summary>
        public EquipmentEnum Type { get; set; }

        /// <summary>
        /// 制造厂家
        /// </summary>
        public string Manufacturer { get; set; }
        /// <summary>
        /// 制造时间
        /// </summary>
        public DateTime? ManufacturerTime { get; set; }

        /// <summary>
        /// 额定转速
        /// </summary>
        public double? RatedSpeed { get; set; }

        /// <summary>
        /// 额定功率
        /// </summary>
        public double? RatedPower { get; set; }


        public Guid UnitId { get; set; }

        public string Language => CultureInfo.CurrentCulture.TwoLetterISOLanguageName;

        /// <summary>
        /// 多语言展示Name
        /// </summary>
        public string DisplayName => GetLocalizedName();

        public ICollection<Component> Components { get; set; } = new List<Component>();

        public Dictionary<string, object> DerivedPropertiesJson { get; set; } = new Dictionary<string, object>();

        public abstract void SerializeProperties(Dictionary<string, object> derivedPropertiesJson);
        public abstract void DeserializeProperties();


        public Equipment SetName(string name)
        {
            Name = Check.NotNullOrEmpty(name, nameof(name), EquipmentConst.MaxNameLength);
            return this;
        }

        public Equipment SetNameEn(string nameen)
        {
            NameEn = Check.NotNullOrEmpty(nameen, nameof(nameen), EquipmentConst.MaxNameLength);
            return this;
        }

        public Equipment SetNumber(int number)
        {
            Number = number;
            return this;
        }

        public Equipment AddComponent(Guid equipmentId, Guid componentId, string name, string nameen, int number, ComponentEnum type, Action<Component> action, IStringLocalizer L)
        {
            var (expression, localizedName) = GetComponentExpression(name, nameen);

            if (Components.Where(expression.Compile()).Any(item => item.Number == number))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.ComponentNameAlreadyExist], PHMEEDomainErrorCodes.ComponentNameAlreadyExist).WithData("Name", localizedName).WithData("Number", number);
            }

            Component component = null;

            switch (type)
            {
                case ComponentEnum.CylinderComponent:
                    component = new CylinderComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.CouplerShaftComponent:
                    component = new CouplerShaftComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.MiddleBearComponent:
                    component = new MiddleBearComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.MiddleShaftComponent:
                    component = new MiddleShaftComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.PropellerShaftComponent:
                    component = new PropellerShaftComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.SternBearComponent:
                    component = new SternBearComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.SternShaftComponent:
                    component = new SternShaftComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.ThrustBearComponent:
                    component = new ThrustBearComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.ThrustShaftComponent:
                    component = new ThrustShaftComponent(componentId, equipmentId, name, nameen, number);
                    break;
                case ComponentEnum.MainBearComponent:
                    component = new MainBearComponent(componentId, equipmentId, name, nameen, number);
                    break;
            }

            action?.Invoke(component);

            Components.Add(component);

            return this;
        }

        public Equipment UpdateComponent(Guid componentId, string name, string nameen, Action<Component> action, IStringLocalizer L)
        {
            var (expression, localizedName) = GetComponentExpression(name, nameen);

            if (Components.Where(expression.Compile()).Any(item => item.Id != componentId))
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.ComponentNameAlreadyExist], PHMEEDomainErrorCodes.ComponentNameAlreadyExist).WithData("Name", localizedName);
            }
            var component = Components.FirstOrDefault(item => item.Id == componentId);
            if (component == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.ComponentNotFound], PHMEEDomainErrorCodes.ComponentNotFound);
            }

            action?.Invoke(component);

            return this;
        }

        public Equipment RemoveComponent(Guid componentId, IStringLocalizer L)
        {
            var component = Components.FirstOrDefault(item => item.Id == componentId);
            if (component == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.ComponentNotFound], PHMEEDomainErrorCodes.ComponentNotFound);
            }

            Components.Remove(component);

            return this;
        }

        public Component GetComponent(Guid componentId, IStringLocalizer L)
        {
            var component = Components.FirstOrDefault(item => item.Id == componentId);
            if (component == null)
            {
                throw new UserFriendlyException(L[PHMEEDomainErrorCodes.ComponentNotFound], PHMEEDomainErrorCodes.ComponentNotFound);
            }

            return component;
        }

        public List<ComponentEnum> GetComponentTypeOptions()
        {
            var dict = GetEquipmentToComponentOptions();

            if (dict.TryGetValue(this.Type, out var componentList))
            {
                return componentList;
            }
            return new List<ComponentEnum>(); // 返回空列表，如果没有匹配项

        }

        public static Dictionary<EquipmentEnum, List<ComponentEnum>> GetEquipmentToComponentOptions()
        {

            var dict = new Dictionary<EquipmentEnum, List<ComponentEnum>>
            {
                { EquipmentEnum.MainEngine, new List<ComponentEnum> { ComponentEnum.CylinderComponent,ComponentEnum.MainBearComponent } },
                { EquipmentEnum.MainGeneratorDiesel, new List<ComponentEnum> { ComponentEnum.CylinderComponent,ComponentEnum.MainBearComponent } },
                { EquipmentEnum.ShaftSystem, new List<ComponentEnum> { ComponentEnum.CouplerShaftComponent, ComponentEnum.MiddleBearComponent,ComponentEnum.MiddleShaftComponent, ComponentEnum.PropellerShaftComponent, ComponentEnum.SternBearComponent,ComponentEnum.SternShaftComponent, ComponentEnum.ThrustBearComponent,ComponentEnum.ThrustShaftComponent } }
            };

            return dict;

        }

        public List<BaseInfoTagEnum> GetEquipmentTagOptions()
        {
            var list = new List<BaseInfoTagEnum>();

            if (!string.IsNullOrEmpty(Tags))
            {
                var arr = Tags.Split(',', StringSplitOptions.RemoveEmptyEntries);

                foreach (var tag in arr)
                {
                    if (Enum.TryParse(tag, out BaseInfoTagEnum result))
                    {
                        list.Add(result);
                    }
                }
            }

            return list;
        }

        public static List<BaseInfoTagEnum> GetLevelTagOptions()
        {
            var list = PHMEECoreHelper.PhmeeGetEnumsFilter<BaseInfoTagEnum>((int)BaseInfoTagEnum.Power);

            return list;

        }


        public (Expression<Func<Component, bool>> Expression, string LocalizedName) GetComponentExpression(string name, string nameen)
        {
            Expression<Func<Component, bool>> expression = item => true;

            string localizedName = string.Empty;

            switch (Language)
            {
                case PhmeeConst.LanguageEn:

                    localizedName = nameen;

                    expression = expression.And(item => item.NameEn == nameen);

                    break;
                default:

                    localizedName = name;

                    expression = expression.And(item => item.Name == name);

                    break;
            }

            return (expression, localizedName);
        }

        private string GetLocalizedName()
        {
            string localizedName = Language switch
            {
                PhmeeConst.LanguageEn => NameEn,
                _ => Name
            };

            return localizedName;
        }

    }
}
